import random
from abc import abstractmethod

from sam import import_csv_path
from sam.util.dbUtil import DB, DEFAULT_PROCESS_DB_CONNECTION_CONFIG
from sam.util.fileUtil2 import read_file, write_file_quick
from sam.util.strUtil import filter_symbol_4_word

TABLE_NAME = "sca_data_process.sca_client_v5_5"


class BaseAccordantCheck(DB):
    """
    target: 检查是否一致
    读取的内容会组装成字典, key: 就是查询的 where 条件; value: 可以是 item 新item 的 keys 是查询的 验证的内容是 item 的 内容
    """

    def __init(self, config=DEFAULT_PROCESS_DB_CONNECTION_CONFIG):
        super().__init__(config=config)

    def assert_read_file_content_is_suitable(self, file_path, import_table_column_list: list = None) -> bool:
        if import_table_column_list:
            self.logger.info(f"将对文件: {file_path} 的内容进行检查...")
            lines = read_file(file_path, is_skip_first_line=False)
            if lines:
                column_line_str = ''.join(lines[0])
                table_column_str = ''.join(import_table_column_list)
                if column_line_str.lower() == table_column_str.lower():
                    column_length = len(import_table_column_list)
                    for line in lines:
                        if line and column_length == len(line):
                            continue
                        else:
                            self.logger.error(f"记录: {line} 长度不够!")
                            self.logger.error(f"注意: 文件: {file_path} 的内容检查不通过")
                            return False
                    self.logger.info(f"文件: {file_path} 的内容检查通过")
                    return True
                else:
                    self.logger.error(f"注意: 文件: {file_path} 的内容检查不通过")
                    return False
            else:
                self.logger.error(f"文件:{file_path} 表头与预设定的表头不一致")
                msg = f"文件: {file_path} 读取到的内容为空."
                raise RuntimeError(msg)
        else:
            self.logger.warn(f"注意: 没有对文件: {file_path} 的内容进行检查.")
            return True

    def do_check(self, table_name: str, need_check_item_list: list, batch_size: int = 500,
                 optional: str = "str") -> tuple:
        """ 检查 """
        accordance_result_list = []
        inconsistent_result_list = []
        temp_source_list = []
        for i, source in enumerate(need_check_item_list):
            temp_source_list.append(source)
            if i > 0 and i % batch_size == 0:
                query_result_list = self.do_query(table_name, temp_source_list, optional=optional)
                temp_inconsistent_list, temp_accordance_list = self.compare(temp_source_list, query_result_list)
                if temp_inconsistent_list:
                    inconsistent_result_list.extend(temp_inconsistent_list)
                if temp_accordance_list:
                    accordance_result_list.extend(temp_accordance_list)
                temp_source_list.clear()
        else:
            query_result_list = self.do_query(table_name, temp_source_list, optional=optional)
            temp_inconsistent_list, temp_accordance_list = self.compare(temp_source_list, query_result_list)
            if temp_inconsistent_list:
                inconsistent_result_list.extend(temp_inconsistent_list)
            if temp_accordance_list:
                accordance_result_list.extend(temp_accordance_list)
            temp_source_list.clear()
        return accordance_result_list, inconsistent_result_list

    def do_query(self, table_name: str, item_list: list, optional: str = "str") -> list:
        if "str" == optional:
            return self.query_by_str(table_name, item_list)
        elif "int" == optional:
            return self.query_by_int(table_name, item_list)
        else:
            msg = f"暂 仅支持 char 或 int , 不支持 {optional}"
            raise RuntimeError(msg)

    def query_by_int(self, table_name: str, item_list: list) -> list:
        column_list = []
        where_value_list = []

        random_index = random.randint(0, len(item_list) - 1)
        random_item = item_list[random_index]
        key_list = list(random_item.keys())
        for i, key in enumerate(key_list):
            column_list.append(f"{key}")
            if i == 0:
                where_key_str = f"{key}"

        for item in item_list:
            value_list = list(item.values())
            for i, value in enumerate(value_list):
                if i == 0:
                    where_value_list.append(f"{value}")

        pre_item_list_str = ",".join(where_value_list)
        where_str = f" {where_key_str} in ({pre_item_list_str}) "
        query_result_list = self.query(
            table_name
            , column=column_list
            , where=where_str
            , optional="dict"
            # , is_only_print_sql=True
        )
        return [{k: str(v) for k, v in item.items()} for item in query_result_list]

    def query_by_str(self, table_name: str, item_list: list) -> list:
        column_list = []
        where_value_list = []

        random_index = random.randint(0, len(item_list))
        random_item = item_list[random_index]
        key_list = list(random_item.keys())
        for i, key in enumerate(key_list):
            column_list.append(f"{key}")
            if i == 0:
                where_key_str = f"{key}"

        for item in item_list:
            value_list = list(item.values())
            for i, value in enumerate(value_list):
                if i == 0:
                    where_value_list.append(f"'{value}'")

        pre_item_list_str = ",".join(where_value_list)
        where_str = f" {where_key_str} in ({pre_item_list_str}) "
        query_result_list = self.query(
            table_name
            , column=column_list
            , where=where_str
            , optional="dict"
            # , is_only_print_sql=True
        )
        return [{k: str(v) for k, v in item.items()} for item in query_result_list]

    @staticmethod
    def compare(item_list: list, query_result_list: list) -> tuple:
        accordance_result_list = []
        inconsistent_result_list = []
        if query_result_list:
            for item in item_list:
                if item in query_result_list:
                    accordance_result_list.append(item)
                else:
                    inconsistent_result_list.append(item)

            return inconsistent_result_list, accordance_result_list
        else:
            inconsistent_result_list = item_list
            return inconsistent_result_list, accordance_result_list


class AccordantCheckByFile(BaseAccordantCheck):
    def __init__(self, config=DEFAULT_PROCESS_DB_CONNECTION_CONFIG):
        super().__init__(config=config)

    @abstractmethod
    def pre_handle_read_lines(self, lines: list) -> list:
        pass

    def check_by_file(self, table_name: str, batch_size: int = 500,
                      import_table_column_list: list = None
                      , is_need_pre_formatter: bool = False
                      , pre_formatter_index: int = 0
                      , export_file_name_suffix: str = None
                      , optional: str = "str"):
        lines = read_file(import_csv_path, is_skip_first_line=False)
        if not self.assert_read_file_content_is_suitable(import_csv_path, import_table_column_list):
            msg = f"文件检查没有通过"
            raise RuntimeError(msg)
        lines = self.pre_handle_read_lines(lines)
        columns = lines.pop(0)
        columns = [col.lower() for col in columns]
        item_list = []
        if is_need_pre_formatter:
            for line in lines:
                item = {}
                for i, col in enumerate(columns):
                    if i == pre_formatter_index:
                        item[col] = filter_symbol_4_word(line[i])
                    else:
                        item[col] = line[i]
                item_list.append(item)
        else:
            for line in lines:
                item = {}
                for i, col in enumerate(columns):
                    item[col] = line[i]
                item_list.append(item)
        accordance_result_list, inconsistent_result_list = self.do_check(table_name, item_list, batch_size,
                                                                         optional=optional)
        export_accordance_list = [list(item.values()) for item in accordance_result_list]
        write_file_quick(export_accordance_list, export_file_name="一致", prefix=table_name,
                         suffix=export_file_name_suffix)
        export_inconsistent_list = [list(item.values()) for item in inconsistent_result_list]
        write_file_quick(export_inconsistent_list, export_file_name="不一致", prefix=table_name,
                         suffix=export_file_name_suffix)
        self.logger.info(f"校验 {export_file_name_suffix} 任务完成")


def manual_check_classify_v5_4():
    process = AccordantCheckByFile()
    process.check_by_file(table_name=TABLE_NAME, batch_size=100, optional="int")


def demo_tt():
    item_list = [{"name": "sam", "id": 1}, {"id": 2, "name": "sam2"}]
    for item in item_list:
        print(item.keys())
        for i, kv in zip(range(len(item)), item.items()):
            print(i, kv)


def demo():
    original_item_list = [{"id": 1031466, "type": 100, "sub_type": 101, "third_type": 10101},
                          {"id": 1031467, "type": 100, "sub_type": 101, "third_type": 10101}]
    query_item_list = [{"id": 1031466, "type": 100, "sub_type": 101, "third_type": 10101},
                       {"id": 1031467, "type": 100, "sub_type": 101, "third_type": 10101}]

    for item in original_item_list:
        if item in query_item_list:
            print(item)
        else:
            print("NO")


if __name__ == "__main__":
    manual_check_classify_v5_4()
